// 题目一：ALU 算术逻辑单元设计

// 模块作用说明：ALU（算术逻辑单元）是处理器中用于执行加减法、逻辑运算、移位等操
// 作的核心模块。本题要求学生基于操作码(op)选择不同的操作类型，实现一套可扩展的通
// 用逻辑单元。
// 1 module alu (
//  2
//  3
//  4
//  5
//  6 );
//  input wire [3:0] op,
//  // 操作码
// input wire [7:0] a, b, // 操作数
// output reg [7:0] result,
//  output reg zero_flag
//  Listing 1: ALU 模块接口示例
// 1
// • 使用case 语句实现常见的操作（加法、减法、与、或、异或、左移、逻辑右移、算术
// 右移等）；
// • 根据结果设置zero_flag（当结果为0时置1）；
// • 编写testbench 进行功能验证。
// 说明：以上操作码的4位二进制编码（instr[7:4]）应由译码器（Decoder）从 8 位指令中提
// 取，并传递给ALU模块作为控制信号。建议在Testbench中使用8’hXY形式手动构造指
// 令（X为操作码，Y为寄存器组合）。


module alu(
    input wire[3:0] op, //操作码
    input wire[7:0] a,b, //操作数
    output reg [7:0] result,
    output reg zero_flag
);

always @(*) begin
    case(op)
        4'h0: begin  //加法
            result = a+b;
        end
        4'h1: begin //减法
            result = a-b;
        end
        4'h2: begin //按位与
            result = a&b;
        end
        4'h3: begin //按位或
            result = a|b;
        end
        4'h4: begin //按位异或
            result = a^b;
        end
        4'h5: begin //左移一位
            result = a<<1;
        end
        4'h6: begin //逻辑右移一位
            result = a>>1;
        end
        4'h7: begin //算术右移一位(带符号)
        //将a转换为有符号数
            result = $signed (a>>>1) ;
        end
        default: begin
            result = 8'b0;
        end
    endcase

    if(result == 8'b0) begin
        zero_flag = 1'b1;
    end
    else begin
        zero_flag = 1'b0;
    end
end

endmodule

//测试文件
`timescale 1ns/100ps
module alu_tb;
    reg[7:0] instr;//8位指令
    reg[7:0] a,b;//操作数
    wire[7:0] result;//结果
    wire zero_flag;

    //从8位指令中提取四位操作码
    wire[3:0] op = instr[7:4];

    //实例化
    alu uut(
        .op(op),
        .a(a),
        .b(b),
        .result(result),
        .zero_flag(zero_flag)
    );

initial begin
    instr = 8'h00; a = 8'd2; b = 8'd5;//测试加法
#10 instr = 8'h10; a = 8'd3; b = 8'd1;//测试减法
#10 instr = 8'h20; a = 8'b00010111; b = 8'b01100010;//测试按位与
#10 instr = 8'h30; a = 8'b00010111; b = 8'b01100010;//测试按位或
#10 instr = 8'h40; a = 8'b00010111; b = 8'b01100010;//测试按位异或
#10 instr = 8'h50; a = 8'b00110110; b = 8'b00000000;//测试a逻辑左移
#10 instr = 8'h60; a = 8'b00110110; b = 8'b00000000;//测试a逻辑右移
#10 instr = 8'h70; a = 8'b11110110; b = 8'b00000000;//测试a算术右移
#10 instr = 8'h10; a = 8'd2; b = 8'd2;//测试零标志位
#10 $stop;
end
endmodule